import React from "react";
// 引入less
import Index from "./index.module.less";
// 引入canvas
import { Canvas } from "../../../public/js/canvas";
// 引入背景图片
import Bg from "../../../public/images/containerBg.png";
// 引入弹窗提示组件
import Prompt from "../../component/prompt/prompt"
// 创建每个模型的数据源
const MODELS = [
  // 第一个模型数据源(田型)
  {
    0: {
      row: 1,
      col: 1,
      color: "#FFFF00",
    },
    1: {
      row: 2,
      col: 1,
      color: "#FFFF00",
    },
    2: {
      row: 1,
      col: 2,
      color: "#FFFF00",
    },
    3: {
      row: 2,
      col: 2,
      color: "#FFFF00",
    },
  },
  // 第二个模型数据源(一型)
  {
    0: {
      row: 0,
      col: 0,
      color: "#0000FF",
    },
    1: {
      row: 0,
      col: 1,
      color: "#0000FF",
    },
    2: {
      row: 0,
      col: 2,
      color: "#0000FF",
    },
    3: {
      row: 0,
      col: 3,
      color: "#0000FF",
    },
  },
  // 第三个模型数据源(凸型)
  {
    0: {
      row: 1,
      col: 1,
      color: "#800080",
    },
    1: {
      row: 2,
      col: 0,
      color: "#800080",
    },
    2: {
      row: 2,
      col: 1,
      color: "#800080",
    },
    3: {
      row: 2,
      col: 2,
      color: "#800080",
    },
  },
  // 第四个模型数据源(S型)
  {
    0: {
      row: 1,
      col: 2,
      color: "#FF0000",
    },
    1: {
      row: 1,
      col: 1,
      color: "#FF0000",
    },
    2: {
      row: 2,
      col: 1,
      color: "#FF0000",
    },
    3: {
      row: 2,
      col: 0,
      color: "#FF0000",
    },
  },
  // 第五个模型数据源(Z型)
  {
    0: {
      row: 1,
      col: 0,
      color: "#008000",
    },
    1: {
      row: 1,
      col: 1,
      color: "#008000",
    },
    2: {
      row: 2,
      col: 1,
      color: "#008000",
    },
    3: {
      row: 2,
      col: 2,
      color: "#008000",
    },
  },
  // 第六个模型数据源(L型)
  {
    0: {
      row: 2,
      col: 0,
      color: "#FFA500",
    },
    1: {
      row: 2,
      col: 1,
      color: "#FFA500",
    },
    2: {
      row: 2,
      col: 2,
      color: "#FFA500",
    },
    3: {
      row: 1,
      col: 2,
      color: "#FFA500",
    },
  },
  // 第七个模型数据源(J型)
  {
    0: {
      row: 1,
      col: 0,
      color: "#FFC0CB",
    },
    1: {
      row: 2,
      col: 0,
      color: "#FFC0CB",
    },
    2: {
      row: 2,
      col: 1,
      color: "#FFC0CB",
    },
    3: {
      row: 2,
      col: 2,
      color: "#FFC0CB",
    },
  },
];
// 每次移动的步长
const STEP = 20;
// 分割容器
// 行
const ROW_COUNT = 18,
  // 列
  COL_COUNT = 10;
// 16宫格中x轴的位置
let currentX = 0,
  // 16宫格中y轴的位置
  currentY = 0;
// 每个方块唯一编号
let id = 0;

// 记录所有块元素的位置
// k=行_列,v=块元素
let fixedBlocks = {};

export default class PageIndex extends React.Component {
  constructor() {
    super();
    this.state = {
      // 判断显示pc还是mobile，0为pc，1为mobile
      isShowWidth: window.innerWidth >= 1080 ? "0" : "1",
      // 是否显示网格线
      isDrawGrid: true,
      // 时分秒
      timeNum: 0,
      // 时
      timeH: 0,
      // 分
      timeM: 0,
      // 秒
      timeS: 0,
      // 计时器
      timer: null,
      // 分数
      score: 0,
      // 最高得分
      maxScore: 0,
      // 下一次使用的数据源
      nextModel: {},
      // 当前使用的数据源
      currentModel: {},
      // 将要在页面上显示的所有子元素方块
      showModel: [],
      // 将要在页面上显示的下次子元素方块
      showNextModel: [],
      // 自动下落的定时器
      mInterval: null,
      // 暂停or开始,0:需要暂停,1:不需要暂停,2:暂停中
      isSuspended: 0,
      // 下落速度的时间，单位ms，初始600ms
      mIntervalTime: 600,
	  // 是否展示背景图
	  isBgShow:false
    };
  }
  // 页面加载
  componentDidMount() {
    //监听窗口大小改变
    window.addEventListener("resize", this.handleResize.bind(this));
    // 监听键盘
    window.addEventListener("keydown", this.onkeydown.bind(this));
    this.init();
  }

  // 页面卸载
  componentWillUnmount() {
    //一定要最后移除监听器，以防多个组件之间导致this的指向紊乱
    window.removeEventListener("resize", this.handleResize.bind(this));
    // 移除键盘监听
    window.removeEventListener("keydown", this.onkeydown.bind(this));
  }

  // 监听窗口大小
  handleResize = (e) => {
    if (e.target.innerWidth >= 1080) {
      this.setState({ isShowWidth: 0, isSuspended: 2 }, () => {
        clearInterval(this.state.timer);
        clearInterval(this.state.mInterval);
      });
    } else this.setState({ isShowWidth: 1 });
  };

  // 窗口加载时执行的函数
  init() {
    if (this.state.isDrawGrid) {
      Canvas.drawGrid("container_canvas", "#fff", 20, 20);
    }
    Canvas.drawGrid("show_canvas", "#fff", 20, 20);
    // 时间记录
    this.setState({
      timeH: this.showNum(parseInt(this.state.timeNum / 60 / 60)),
      timeM: this.showNum(parseInt(this.state.timeNum / 60) % 60),
      timeS: this.showNum(this.state.timeNum % 60),
      // 给最高记录赋值
      maxScore:
        localStorage.getItem("maxscore") === null
          ? 0
          : localStorage.getItem("maxscore"),
    });
    // 创建块元素事件调用
    this.createModel();
    // 开启定时器记录时间
    this.timing();
  }

  // 封装处理单位数字的函数
  showNum(num) {
    if (num < 10) return "0" + num;
    return num;
  }

  // 随机创建方块
  randomModel() {
    let List = {
      temporaryList:[],
      nextModelList:[]
    }
    List.temporaryList = JSON.stringify(this.state.nextModel) === "{}"
      ? MODELS[parseInt(MODELS.length * Math.random())]
      : this.state.nextModel;
    List.nextModelList = MODELS[parseInt(MODELS.length * Math.random())];

    // if (this.isMeet(currentX, currentY, List.temporaryList)) {
    //   this.randomModel();
    // }
    return List;
  }

  // 根据模型的数据创建对应的块元素
  createModel() {
    if (this.isGameOver()) {
      this.gameOver();
      return false;
    }
    let currentModelList = [];
    // 重新初始化16宫格的位置
    currentX = 0;
    currentY = 0;
    
    let temporaryList = this.randomModel().temporaryList,
      nextModelList = this.randomModel().nextModelList;
    // if (this.isMeet(currentX, currentY, this.randomModel().temporaryList)) {
    //   temporaryList = this.randomModel().temporaryList;
    //   nextModelList = this.randomModel().nextModelList;
    // }

    // 生成对应数量的块元素
    for (let key in temporaryList) {
      currentModelList[key] = {
        id: id,
        col: temporaryList[key].col,
        row: temporaryList[key].row,
        classname: Index.activity_model,
        top: 0,
        left: 0,
        color: temporaryList[key].color,
      };
      id++;
    }
    this.setState(
      {
        // 给输出对象赋值
        currentModel: currentModelList,
        nextModel:nextModelList
      },
      () => {
        // 给下一个使用的数据源定位
        this.nextLocation();
        // 给当前游戏显示方块定位
        this.locationBlocks();
        // 调用模型自动下落事件
        this.autoDown();
      }
    );
  }

  // 根据数据源指定块元素的位置
  locationBlocks() {
    // 判断块元素的越界行为
    this.checkBound();
    // 1.拿到所有的块元素
    let currentModelList = this.state.currentModel;
    for (let i = 0; i < currentModelList.length; i++) {
      // 1.找到每个块元素的对应的位置参数
      let blockModel = this.state.currentModel[i];
      // 2.根据每个块元素对应的数据来指定位置
      // 每个块元素的位置由2个值确定
      // 1.16宫格的位置,
      // 2.该块元素在16宫格中的位置
      currentModelList[i].top = (currentY + blockModel.row) * STEP + "px";
      currentModelList[i].left = (currentX + blockModel.col) * STEP + "px";
    }
    this.showBox(currentModelList);
    this.setState({
      currentModel: currentModelList,
    });
  }

  // 将当前显示的方块添加到所有方块里
  showBox(list) {
    let showModelList = this.state.showModel;
    list.forEach((item, index) => {
      showModelList[item.id] = {
        id: item.id,
        col: item.col,
        row: item.row,
        classname: item.classname,
        top: item.top,
        left: item.left,
        color: item.color,
      };
    });
    this.setState({ showModel: showModelList });
  }

  // 下次使用的数据源定位
  nextLocation() {
    let showNextModelList = [];
    // 创建块元素
    for (let key in this.state.nextModel) {
      showNextModelList[key] = {
        classname: Index.next_activity_model,
        top: 0,
        left: 0,
      };
    }
    // 获得块元素
    for (let i = 0; i < showNextModelList.length; i++) {
      // 1.找到每个块元素的对应的位置参数
      let blockModel = this.state.nextModel[i];
      // 2.根据每个块元素对应的数据来指定位置
      showNextModelList[i].top = blockModel.row * STEP + "px";
      showNextModelList[i].left = blockModel.col * STEP + "px";
      this.setState({
        showNextModel: showNextModelList,
      });
    }
  }

  // 监听用户键盘事件
  onkeydown = (e) => {
	console.log(e.keyCode)
    switch (e.keyCode) {
      // 用户按下"左"键
      case 37:
        if (this.state.isSuspended === 2) return false;
        this.move(-1, 0);
        break;
      // 用户按下"上"键
      case 38:
        if (this.state.isSuspended === 2) return false;
        this.rotate();
        break;
      // 用户按下"右"键
      case 39:
        if (this.state.isSuspended === 2) return false;
        this.move(1, 0);
        break;
      // 用户按下"下"键
      case 40:
        if (this.state.isSuspended === 2) return false;
        this.move(0, 1);
        break;
      // 直接下降
      case 32:
        if (this.state.isSuspended === 2) return false;
        this.autoDown(0);
        break;
		// 显示背景图
	  case 66:
		  let isBgShow = !this.state.isBgShow;
		  this.setState({ isBgShow: isBgShow });
		  console.log(isBgShow)
		  break;
      // 按c暂停/开始
      case 67:
        this.suspended();
        break;
      // 按回车重新开始
      case 13:
        this.start();
        break;
      default:
        break;
    }
  };

  // 旋转模型
  rotate() {
    // 旋转算法
    // 旋转后的行=旋转前的列
    // 旋转后的列=3-旋转前的行

    // 克隆currentModel
    let cloneCurrentModel = this.state.currentModel;

    // 遍历数据源
    cloneCurrentModel.forEach((item) => {
      let temp = item.row;
      item.row = item.col;
      item.col = 3 - temp;
    });

    // 如果旋转之后会发生触碰,则不需要此次旋转
    if (this.isMeet(currentX, currentY, cloneCurrentModel)) {
      return false;
    }

    // 接受这次旋转
    this.setState(
      {
        currentModel: cloneCurrentModel,
      },
      () => {
        // 重新定位
        this.locationBlocks();
      }
    );
  }

  // 移动事件
  move(x, y) {
    if (this.isMeet(currentX + x, currentY + y, this.state.currentModel)) {
      // 底部的触碰发生在移动16宫格的时候,并且此次移动是因为Y轴的变化而引起的
      if (y !== 0) {
        // 模型之间底部发生触碰了
        this.fixedBottomModel();
      }
      return false;
    }
    // 每次移动,16宫格在动
    currentX += x;
    currentY += y;
    this.locationBlocks();
  }

  // 判断模型之间的触碰
  // x,y表示16宫格将要移动到的位置,model表示当前模型数据源将要完成的变化
  isMeet(x, y, model) {
    // 模型之间的触碰,如果在一个固定的位置已经存在一个被固定的块元素时,那么活动中的模型不能再占用该位置
    // 判断触碰,即判断活动中的模型将要活动到的位置是否已经存在被固定的块元素，如果存在返回true，表示将要移动到的位置会发生触碰，否则就返回false
    for (let k in model) {
      let blockModel = model[k];
      // 该位置是否已经存在块元素
      if (
        fixedBlocks[y + blockModel.row + "_" + (x + blockModel.col)] !==
        undefined
      )
        return true;
    }
    return false;
  }

  // 控制模型只能在容器中移动
  checkBound() {
    // 定义模型可以活动的边界
    let leftBound = 0,
      rightBound = COL_COUNT,
      bottomBound = ROW_COUNT;
    // 当模型中有一个块元素超出了边界之后,让16宫格后退一格
    for (let key in this.state.currentModel) {
      // 块元素的数据
      let blockModel = this.state.currentModel[key];
      // 左侧越界
      if (blockModel.col + currentX < leftBound) {
        currentX++;
      }
      // 右侧越界
      if (blockModel.col + currentX >= rightBound) currentX--;
      // 底部越界
      if (blockModel.row + currentY >= bottomBound) {
        currentY--;
        // 把模型固定在底部
        this.fixedBottomModel();
      }
    }
  }

  // 把模型固定底部并且变色
  fixedBottomModel() {
    // 1.改版模型中每一个块元素的样式
    // 2.让模型不可以在进行移动
    let currentModelList = this.state.currentModel;
    currentModelList.forEach((item, index) => {
      // 更改块元素的类名
      item.classname = Index.fixed_model;
      // 把该块元素放入变量中
      fixedBlocks[currentY + item.row + "_" + (currentX + item.col)] = item.id;
    });
    this.showBox(currentModelList);

    // 判断一行是否被铺满
    this.isRemoveLine();

    // // 3.创建新的模型
    this.createModel();
  }

  // 判断一行是否被铺满
  isRemoveLine() {
    // 在一行中每一列都存在块元素，那么该行就需要被清理了
    // 遍历所有行中的所有列
    // 遍历所有行
    for (let i = 0; i < ROW_COUNT; i++) {
      // 标记符,假设当前行被铺满了
      let flag = true;
      // 遍历当前行中的所有列
      for (let j = 0; j < COL_COUNT; j++) {
        // 如果当前行中有一列没有数据,那么就说明当前行没有被铺满
        if (fixedBlocks[i + "_" + j] === undefined) {
          flag = false;
          break;
        }
      }
      if (flag) {
        // 该行已经被铺满了
        this.removeLine(i);
      }
    }
  }

  // 清理被铺满的这一行
  removeLine(line) {
    let fixedBlocksList = fixedBlocks;
    let score = this.state.score;
    let showModelList = this.state.showModel;
    for (let i = 0; i < COL_COUNT; i++) {
      // 1.删除该行中所有的块元素
      this.state.showModel.forEach((item, index) => {
        if (parseInt(item.id) === parseInt(fixedBlocksList[line + "_" + i])) {
          showModelList.splice(index, 1);
        }
      });
      // 2.删除该行中所有块元素的数据源
      delete fixedBlocksList[line + "_" + i];
    }
    // 每次得分加10
    score += 10;
    fixedBlocks = fixedBlocksList;
    this.setState(
      {
        showModel: showModelList,
        score: score,
      },
      () => {
        this.downLine(line);
        this.gameDifficulty();
      }
    );
  }

  // 让被清理行之上的块元素下落
  downLine(line) {
    let fixedBlocksList = fixedBlocks;
    let showModelList = this.state.showModel;
    // 遍历被清理行之上的所有行
    for (let i = line - 1; i >= 0; i--) {
      // 该行中的所有列
      for (let j = 0; j < COL_COUNT; j++) {
        if (fixedBlocksList[i + "_" + j] === undefined) continue;
        // 存在数据
        // 1.被清理行之上的所有块元素数据源所在的行数+1
        fixedBlocksList[i + 1 + "_" + j] = fixedBlocksList[i + "_" + j];
        // 2.让块元素在容器中的位置下落
        showModelList.forEach((item) => {
          if (
            parseInt(item.id) === parseInt(fixedBlocksList[i + 1 + "_" + j])
          ) {
            item.top = (i + 1) * STEP + "px";
          }
        });
        // 3.清理掉之前的块元素
        delete fixedBlocksList[i + "_" + j];
      }
    }
    fixedBlocks = fixedBlocksList;
    this.setState({ showModel: showModelList });
  }

  // 判断游戏是否结束
  isGameOver() {
    // 当第0行存在块元素的时候,表示游戏结束了
    for (let i = 0; i < COL_COUNT; i++) {
      if (fixedBlocks["0_" + i] !== undefined) return true;
    }
    return false;
  }

  // 结束掉游戏
  gameOver() {
    // 1.停止自动下落定时器
    if (this.state.mInterval) clearInterval(this.state.mInterval);
    // 停止计时器
    if (this.state.timer) clearInterval(this.state.timer);
    // 弹出对话框
    alert("游戏结束,请重新开始");
  }

  // 模型自动下落
  autoDown(time) {
    if (this.state.mInterval) clearInterval(this.state.mInterval);
    this.setState({
      mInterval: setInterval(
        () => {
          this.move(0, 1);
        },
        time === undefined ? this.state.mIntervalTime : time
      ),
    });
  }

  // 暂停or开始
  suspended() {
    if (parseInt(this.state.isSuspended) === 0) {
      clearInterval(this.state.mInterval);
      clearInterval(this.state.timer);
      this.setState({
        isSuspended: 2,
      });
    } else {
      this.autoDown();
      this.timing();
      this.setState({
        isSuspended: 0,
      });
    }
  }

  // 计时器
  timing() {
    if (this.state.timer) clearInterval(this.state.timer);
    let timeNum = this.state.timeNum;
    this.setState({
      timer: setInterval(() => {
        timeNum++;
        this.setState({
          timeNum: timeNum,
          timeH: this.showNum(parseInt(timeNum / 60 / 60)),
          timeM: this.showNum(parseInt(timeNum / 60) % 60),
          timeS: this.showNum(timeNum % 60),
        });
      }, 1000),
      timeNum: timeNum,
    });
  }

  // 重新开始事件
  start() {
    clearInterval(this.state.timer);
    clearInterval(this.state.mInterval);
    currentX = 0;
    currentY = 0;
    id = 0;
    fixedBlocks = {};
    this.setState(
      {
        timeNum: 0,
        score: 0,
        maxScore: this.state.score,
        currentModel: {},
        showNextModel: [],
        showModel: [],
        nextModel: {},
        isSuspended: 0,
        isDrawGrid: true,
      },
      () => {
        this.isLocalStorage();
        this.init();
      }
    );
  }

  // 在游戏重新开始的时候将数据保存在浏览器中
  isLocalStorage() {
    let maxscore = this.state.maxScore;
    if (localStorage.getItem("maxscore") !== null) {
      if (localStorage.getItem("maxscore") <= maxscore) {
        localStorage.setItem("maxscore", maxscore);
      }
    } else {
      localStorage.setItem("maxscore", maxscore);
    }
  }

  // 判断分数增加游戏难度
  gameDifficulty() {
    if (this.state.score >= 100) {
      this.setState({ mIntervalTime: 500 });
      return false;
    } else if (this.state.score >= 300) {
      this.setState({ mIntervalTime: 300 });
      return false;
    } else if (this.state.score >= 500) {
      this.setState({ mIntervalTime: 200 });
      return false;
    } else if (this.state.score >= 700) {
      this.setState({ mIntervalTime: 100 });
      return false;
    }
  }

  render() {
    return (
      <div className={Index.main}>
        {parseInt(this.state.isShowWidth) === 0 ? (
          <div className={Index.pc_ver}>
            <div className={Index.box_cont}>
              <h1 className={Index.box_cont_title}>俄罗斯方块</h1>
              {/* 背景容器 */}
              <div
                id="container"
                className={Index.container}
                style={{ background: `url('${this.state.isBgShow ? Bg : ''}') no-repeat` }}
              >
                <canvas id="container_canvas" width="200" height="360"></canvas>
                {/* 每一个小方块 */}
                {this.state.showModel !== null
                  ? this.state.showModel.map((item, index) => {
                      return (
                        <div
                          key={index}
                          className={item.classname}
                          style={{
                            top: item.top,
                            left: item.left,
                            backgroundColor: item.color,
                          }}
                        ></div>
                      );
                    })
                  : ""}
              </div>
            </div>
            {/* 展示 */}
            <div className={Index.box_show}>
              {/* 下一块 */}
              <h3>下一块</h3>
              <div className={Index.box_show_block} id="box-show-block">
                <canvas id="show_canvas" width="80px" height="80px"></canvas>
                {/* 每一个小方块 */}
                {this.state.showNextModel !== null
                  ? this.state.showNextModel.map((item, index) => {
                      return (
                        <div
                          key={index}
                          className={item.classname}
                          style={{ top: item.top, left: item.left }}
                        ></div>
                      );
                    })
                  : ""}
              </div>
              {/* 展示得分等数据 */}
              <div className={Index.box_show_data}>
                <div className={Index.box_show_item}>
                  <div className={Index.box_show_item_txt}>时间</div>：
                  <div>
                    <span
                      className={`${Index.box_show_item_val} ${
                        this.state.isDrawGrid ? Index.timeH : ""
                      }`}
                    >
                      {this.state.timeH}
                    </span>
                    H
                    <span
                      className={`${Index.box_show_item_val} ${Index.timeM}`}
                    >
                      {this.state.timeM}
                    </span>
                    M
                    <span
                      className={`${Index.box_show_item_val} ${Index.timeS}`}
                    >
                      {this.state.timeS}
                    </span>
                    S
                  </div>
                </div>
                <div className={Index.box_show_item}>
                  <div className={Index.box_show_item_txt}>得分</div>：
                  <div className={`${Index.box_show_item_val} ${Index.score}`}>
                    {this.state.score}
                  </div>
                  分
                </div>
                <div className={Index.box_show_item}>
                  <div className={Index.box_show_item_txt}>最高得分</div>：
                  <div
                    className={`${Index.box_show_item_val} ${Index.maxScore}`}
                  >
                    {this.state.maxScore}
                  </div>
                  分
                </div>
              </div>
              {/* 按钮 */}
              <div className={Index.box_show_btngroup}>
                <div className={Index.box_show_btn}>
                  <button type="button" className={Index.start} onClick={this.start.bind(this)}>
                    重新开始(Enter)
                  </button>
                </div>
                <div className={Index.box_show_btn}>
                  <button type="button" className={Index.suspended} onClick={this.suspended.bind(this)}>
                    暂停/开始(C)
                  </button>
                </div>
              </div>
            </div>
            {/* {} */}
            {/* <Prompt title="提示信息" txt="您确定要重新开始游戏吗？"></Prompt> */}
          </div>
        ) : (
          <div className={Index.mobile_ver}>
              <div className={Index.box}>这是mobile</div>
              {/* <canvas id="container_canvas" width="200" height="360"></canvas>
              <canvas id="show_canvas" width="200" height="360"></canvas>
              <Prompt title="提示信息" txt="您确定要重新开始游戏吗？"></Prompt> */}
          </div>
        )}
      </div>
    );
  }
}
